var app = WebApplication.Create();

app.UseMiddleware<MiddlewareHtml>();
app.UseMiddleware<MiddlewareTitle>();

app.MapWhen(context => context.Request.Path.StartsWithSegments("/map-when-example"), appBuilder => appBuilder.UseMiddleware<MiddlewareUsedByMapWhen>());
app.UseWhen(context => context.Request.Path.StartsWithSegments("/use-when-example"), appBuilder => appBuilder.UseMiddleware<MiddlewareUsedByUseWhen>());

app.UseMiddleware<MiddlewareNavigation>();
app.UseMiddleware<MiddlewareFooter>();

app.Run();

public class MiddlewareHtml
{
    readonly RequestDelegate _next;

    public MiddlewareHtml(RequestDelegate next) => _next = next;

    public async Task Invoke(HttpContext context)
    {
        context.Items["Content"] += "<html><body>\n";
        await _next.Invoke(context);
        context.Items["Content"] += "</body></html>";

        context.Response.Headers.Append("content-type", "text/html");
        await context.Response.WriteAsync(context.Items["Content"] as string);
    }
}

public class MiddlewareTitle
{
    readonly RequestDelegate _next;

    public MiddlewareTitle(RequestDelegate next) => _next = next;

    public async Task Invoke(HttpContext context)
    {
        context.Items["Content"] += "<h1>Contrasting MapWhen with UseWhen</h1>\n";
        await _next.Invoke(context);
    }
}

public class MiddlewareFooter
{
    readonly RequestDelegate _next;

    public MiddlewareFooter(RequestDelegate next) => _next = next;

    public async Task Invoke(HttpContext context)
    {
        await _next.Invoke(context);
        context.Items["Content"] += "<footer><hr/><strong>Middleware Footer</strong></footer>\n";
    }
}


public class MiddlewareUsedByMapWhen
{
    readonly RequestDelegate _next;

    public MiddlewareUsedByMapWhen(RequestDelegate next) => _next = next;

    public async Task Invoke(HttpContext context)
    {
        context.Items["Content"] += @"<strong>This message generated by MiddlewareUsedByMapWhen</strong>\n
            <p>
                MapWhen branches the middleware execution hence you will not see the footer here.
            </p>
            ";

        await _next.Invoke(context);
    }
}

public class MiddlewareUsedByUseWhen
{
    readonly RequestDelegate _next;

    public MiddlewareUsedByUseWhen(RequestDelegate next) => _next = next;

    public async Task Invoke(HttpContext context)
    {
        context.Items["Content"] += @"<strong>This message generated by MiddlewareUsedByUseWhen</strong>\n
            <p>
                UseWhen makes the execution of a Middleware conditional based on certain condition. In contrast with MapWhen, it does not branch the execution. Hence you will
                see the footer here.
            </p>
            ";

        await _next.Invoke(context);
    }
}

public class MiddlewareNavigation
{
    readonly RequestDelegate _next;

    public MiddlewareNavigation(RequestDelegate next) => _next = next;

    public async Task Invoke(HttpContext context)
    {
        context.Items["Content"] += @"<ul>
                   <li><a href=""/map-when-example"">/map-when-example</a>.</li>
                   <li><a href=""/use-when-example"">/use-when-example</a>.</li>
                </ul>";

        await _next.Invoke(context);
    }
}

